<template>
  <div
    class="slider__button-wrapper"
    @mouseenter="handleMouseEnter"
    @mouseleave="handleMouseLeave"
    @mousedown="onButtonDown"
    :class="{ 'hover': hovering, 'dragging': dragging }"
    :style="wrapperStyle"
    ref="button">

    <div class="slider-text-button"  :class="{ 'no-tip': !showTooltip}">
      <span class="slider-text" v-show="showTooltip">{{ formatValue }}</span>
      <div class="slider__button" :class="{ 'hover': hovering, 'dragging': dragging }"></div>
    </div>

  </div>
</template>

<script>
  export default {
    components: {
    },

    props: {
      value: {
        type: Number,
        default: 0
      },
      vertical: {
        type: Boolean,
        default: false
      }
    },

    mounted () {

    },
    data () {
      return {
        hovering: false,
        dragging: false,
        showPopper: false,
        startX: 0,
        currentX: 0,
        startY: 0,
        currentY: 0,
        startPosition: 0,
        newPosition: null,
        oldValue: this.value
      }
    },

    computed: {
      disabled () {
        return this.$parent.field.disabled
      },

      max () {
        return this.$parent.field.max
      },

      min () {
        return this.$parent.field.min
      },

      showTooltip () {
        return this.$parent.field.showTooltip
      },

      precision () {
        return this.$parent.precision
      },

      currentPosition () {
        return `${(this.value - this.min) / (this.max - this.min) * 100}%`
      },

      enableFormat () {
        return this.$parent.formatTooltip instanceof Function
      },

      formatValue () {
        return this.enableFormat && this.$parent.formatTooltip(this.value) || this.value
      },

      wrapperStyle () {
        return this.vertical ? { bottom: this.currentPosition } : { left: this.currentPosition }
      }
    },

    watch: {
      dragging (val) {
        this.$parent.dragging = val
      }
    },

    methods: {
      handleMouseEnter () {
        this.hovering = true
      },

      handleMouseLeave () {
        this.hovering = false
      },

      onButtonDown (event) {
        if (this.disabled) return
        event.preventDefault()
        this.onDragStart(event)
        window.addEventListener('mousemove', this.onDragging)
        window.addEventListener('mouseup', this.onDragEnd)
        window.addEventListener('contextmenu', this.onDragEnd)
      },

      onDragStart (event) {
        this.dragging = true
        if (this.vertical) {
          this.startY = event.clientY
        } else {
          this.startX = event.clientX
        }
        this.startPosition = parseFloat(this.currentPosition)
      },

      onDragging (event) {
        if (this.dragging) {
          let diff = 0
          if (this.vertical) {
            this.currentY = event.clientY
            diff = (this.startY - this.currentY) / this.$parent.$sliderSize * 100
          } else {
            this.currentX = event.clientX
            diff = (this.currentX - this.startX) / this.$parent.$sliderSize * 100
          }
          this.newPosition = this.startPosition + diff
          this.setPosition(this.newPosition)
        }
      },

      onDragEnd (event) {
        event.preventDefault()
        if (this.dragging) {
          /*
           * 防止在 mouseup 后立即触发 click，导致滑块有几率产生一小段位移
           * 不使用 preventDefault 是因为 mouseup 和 click 没有注册在同一个 DOM 上
           */
          setTimeout(() => {
            this.dragging = false
            this.setPosition(this.newPosition)
          }, 0)
          window.removeEventListener('mousemove', this.onDragging)
          window.removeEventListener('mouseup', this.onDragEnd)
          window.removeEventListener('contextmenu', this.onDragEnd)
        }
      },

      setPosition (newPosition) {
        if (newPosition < 0) {
          newPosition = 0
        } else if (newPosition > 100) {
          newPosition = 100
        }
        const lengthPerStep = 100 / (this.max - this.min)
        const steps = Math.round(newPosition / lengthPerStep)
        let value = steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min
        value = parseFloat(value.toFixed(this.precision))
        this.$emit('input', value)
        if (!this.dragging && this.value !== this.oldValue) {
          this.oldValue = this.value
        }
      }
    }
  }
</script>

<style>
  .slider__button-wrapper {
    width: 36px;
    height: 36px;
    position: absolute;
    z-index: 1001;
    top: -16px;
    transform: translateX(-50%);
    background-color: transparent;
    text-align: center;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }
  .slider__button-wrapper .slider-text-button{
    vertical-align: middle;
    display: inline-block;
    position: relative;
    top: -10px;
  }

  .slider__button-wrapper .slider-text-button.no-tip{
    top:0px;
  }

  .slider__button-wrapper:after {
    display: inline-block;
    content: "";
    height: 100%;
    vertical-align: middle;
  }

  .slider__button {
    width: 12px;
    height: 12px;
    background-color: #20a0ff;
    border-radius: 50%;
    transition: .2s;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }

  .slider__button.hover{
    transform: scale(1.5);
    background-color: #1c8de0;
  }

  .slider__button.dragging{
    transform: scale(1.5);
    background-color: #1c8de0;
  }

  .slider-text{
    /*position:relative;*/
    /*right: 5px;*/
  }

  .slider__button-wrapper:after {
    display: inline-block;
    content: "";
    height: 100%;
    vertical-align: middle;
  }
</style>
